<?php

namespace otherLibrary;

use think\facade\Cache;

class FTPClient {
    private $ftpServer;      // FTP服务器地址
    private $ftpUsername;    // FTP登录用户名
    private $ftpPassword;    // FTP登录密码
    private $connId;         // FTP连接资源标识
    private $output = false;         //是否输出信息

    /**
     * 构造方法，初始化FTPClient类实例。
     *
     * @param string $ftpServer   FTP服务器地址。
     * @param string $ftpUsername FTP登录用户名。
     * @param string $ftpPassword FTP登录密码。
     */
    public function __construct($ftpServer, $ftpUsername, $ftpPassword) {
        $this->ftpServer = $ftpServer;
        $this->ftpUsername = $ftpUsername;
        $this->ftpPassword = $ftpPassword;
    }

    public function set_output($output){
        $this->output = $output;
    }

    /**
     * 连接到FTP服务器。
     *
     * @return bool 如果连接成功则返回true，否则返回false。
     */
    public function connect() {
        $this->connId = ftp_connect($this->ftpServer);
        if ($this->connId && ftp_login($this->connId, $this->ftpUsername, $this->ftpPassword)) {
//            $this->output && print_r("已连接到{$this->ftpServer}，登录用户为{$this->ftpUsername}\n");
            ftp_pasv($this->connId, true); // 开启被动模式
            return true;
        } else {
            $this->output && print_r( "无法连接到FTP服务器：{$this->ftpServer}\n");
            return false;
        }
    }

    /**
     * 断开与FTP服务器的连接。
     */
    public function disconnect() {
        if ($this->connId) {
            ftp_close($this->connId);
            $this->output && print_r("已断开与FTP服务器的连接\n");
        }
    }

    /**
     * 处理FTP服务器上的文件。
     *
     * @param string $remoteDir 远程FTP目录。
     * @param string $localRootDir 本地根目录。
     */
    public function processFiles($remoteDir, $localRootDir) {
        if (!$this->connId) {
            $this->output && print_r("未连接到FTP\n");
            return false;
        }

        // 使用 cURL 获取文件列表
        $fileList = $this->getFileListWithCurl($remoteDir);
        $this->output && print_r("\n当前时间" . date('Y-m-d H:i:s') . "开始检测文件列表\n");
        $this->output && print_r($fileList);
        $this->output && print_r("\n当前时间" . date('Y-m-d H:i:s') . "检测结束\n");
        if ($fileList === false) {
            $this->output && print_r("无法获取文件列表\n");
            return false;
        }

        // 迭代处理文件
//        dump($fileList);die();
        foreach ($fileList as $file) {
            //文件名后缀.status 代表一个开关文件。如果存在.status文件 才可以处理不包含后缀的文件
            // 如：file111.status存在，那么就可以处理同目录下（不包含扩展名）file111文件
            if (pathinfo($file, PATHINFO_EXTENSION) == 'status') {
                $baseName = pathinfo($file, PATHINFO_FILENAME);
                $actualFile = $remoteDir . '/' . $baseName;

                //自己上传的文件，不要处理，是给对方ftp操作员处理的
                if(in_array($baseName,['MM004Ij','MM025Ij','SD004Ij','SD033Ij'])) continue;

//                dd($actualFile);
                // 如果文件有效，则下载处理
                if ($this->isValidFile($actualFile)) {
                    $this->downloadAndProcessFileWithCurl($actualFile, $baseName, $remoteDir, $localRootDir);
                }
            }
        }
    }

    /**
     * 使用 cURL 获取指定目录下的文件列表。
     *
     * @param string $remoteDir 远程FTP目录。
     * @return array|false 返回文件列表数组，失败时返回 false。
     */
    private function getFileListWithCurl($remoteDir) {
        $ch = curl_init();
        // 设置 cURL 选项
        curl_setopt($ch, CURLOPT_URL, "ftp://{$this->ftpServer}/");
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_USERPWD, "{$this->ftpUsername}:{$this->ftpPassword}");
        curl_setopt($ch, CURLOPT_TIMEOUT, 30);
        // 禁用 FTP SSL
        curl_setopt($ch, CURLOPT_USE_SSL, false);
        // 发送 CWD 命令切换到指定目录
//        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'CWD ' . '/JYL/trans');
//        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'CWD ' . '/default/abc');
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'CWD ' . $remoteDir);
        curl_exec($ch);
        // 发送 NLST 命令获取文件列表
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'NLST');
        $response = curl_exec($ch);
        curl_close($ch);

        $fileList = explode("\n", trim($response));
        return array_values(array_filter($fileList, function($file) {
            return !in_array($file, array('.', '..'));
        }));
    }

    /**
     * 检查文件是否有效。
     *
     * @param string $remoteFile 远程文件路径。
     * @return bool 如果文件存在且非空则返回true，否则返回false。
     */
    private function isValidFile($remoteFile) {
        $size = ftp_size($this->connId, $remoteFile);
        return $size > 0;
    }

    /**
     * 下载并处理文件。
     *
     * @param string $remoteFile 远程文件路径。
     * @param string $baseName 文件基础名称。
     * @param string $remoteDir 远程FTP目录。
     * @param string $localRootDir 本地根目录。
     */
    private function downloadAndProcessFileWithCurl($remoteFile, $baseName, $remoteDir, $localRootDir) {
        //先删除.status文件
        $this->deleteFile($remoteFile . '.status');

        $localDir = $this->createLocalDir($localRootDir);
        $localPath = $localDir . '/' . $baseName;

        $fp = fopen($localPath, 'w');

        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, "ftp://{$this->ftpServer}/{$remoteFile}");
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_USERPWD, "{$this->ftpUsername}:{$this->ftpPassword}");
        curl_setopt($ch, CURLOPT_USE_SSL, false);
        curl_setopt($ch, CURLOPT_FILE, $fp);

        $success = curl_exec($ch);
        curl_close($ch);
        fclose($fp);

        if ($success) {
            $this->output && print_r("成功下载 $remoteFile 到 $localPath\n");

            // 获取当前时间的小时数
            $currentHour = date('G'); // 'G' 表示24小时制的小时数，不带前导零
            // 晚上8点对应的小时数是20
            $nightHour = 20;
            // 如果当前小时数大于或等于20，则输出提示信息
            if ($currentHour >= $nightHour) {
                $this->output && print_r("当前时间段 {$currentHour} 允许删除操作\n");
                // 删除FTP上的数据文件
                $this->deleteFile($remoteFile);
            } else {
                $this->output && print_r("当前时间段 {$currentHour} 不不不不不不不允许删除操作\n");
            }

//            // 删除FTP上的数据文件
//            $this->deleteFile($remoteFile);

            // 在FTP上创建新的.status文件
            $this->createEmptyFile($remoteDir, $baseName . '.status');
        } else {
            $this->output && print_r("下载 $remoteFile 失败\n");
        }
    }
    /**
     * 创建本地目录。
     *
     * @param string $localRootDir 本地根目录。
     * @return string 返回创建的本地目录路径。
     */
    private function createLocalDir($localRootDir) {
        $dateTime = date('Y/m/d/Hi');
        $localDir = $localRootDir . '/' . $dateTime;
        Cache::set('edi_current_path',$localDir);
        if (!is_dir($localDir)) {
            mkdir($localDir, 0777, true);
        }
        return $localDir;
    }

    /**
     * 在FTP服务器上创建空文件。
     *
     * @param string $remoteDir 远程FTP目录。
     * @param string $fileName 文件名称。
     * @return bool 如果创建成功则返回true，否则返回false。
     */
    private function createEmptyFile($remoteDir, $fileName) {
        $ch = curl_init();

//        $fileName .= '.new';

        curl_setopt($ch, CURLOPT_URL, "ftp://{$this->ftpServer}{$remoteDir}/{$fileName}");
        curl_setopt($ch, CURLOPT_USERPWD, "{$this->ftpUsername}:{$this->ftpPassword}");
        curl_setopt($ch, CURLOPT_UPLOAD, true);
//        curl_setopt($ch, CURLOPT_VERBOSE, true); // 调试模式，输出详细信息
        curl_setopt($ch, CURLOPT_USE_SSL, false); // 调试模式，输出详细信息

        $success = curl_exec($ch);

        curl_close($ch);

        if ($success) {
            $this->output && print_r( "成功在FTP上创建文件: $remoteDir/$fileName\n");
            return true;
        } else {
            $this->output && print_r( "创建文件失败: $remoteDir/$fileName\n");
            return false;
        }
    }
    /**
     * 删除FTP服务器上的文件。
     *
     * @param string $remoteFile 远程文件路径。
     * @return bool 如果删除成功则返回true，否则返回false。
     */
    private function deleteFile($remoteFile) {
        $delete = ftp_delete($this->connId, $remoteFile);

        if ($delete) {
            $this->output && print_r("成功删除文件: $remoteFile\n");
            return true;
        } else {
            $this->output && print_r("删除文件失败: $remoteFile\n");
            return false;
        }
    }

    ///////新写入
    /**
     * 往FTP服务器上的文件写入数据（存在文件则追加，不存在则创建并写入）。
     *
     * @param string $fileName 文件名称（如：MM004IJ）。
     * @param string $data 要写入的数据。
     * @param string $remoteDir 远程FTP目录。
     */
    public function writeToFile($fileName, $data, $remoteDir) {
        // 获取文件列表
        $fileList = $this->getFileListWithCurl($remoteDir);

        // 检查.status文件是否存在
        $statusFile = "{$fileName}.status";
        if (!in_array($statusFile, $fileList)) {
            $this->output && print_r("状态文件{$remoteDir}/{$statusFile}不存在，无法写入数据。\n");
            return false;
        }

        // 删除.status文件
        $this->deleteFile("{$remoteDir}/{$statusFile}");

        // 检查目标文件是否存在
        $remoteFile = "{$remoteDir}/{$fileName}";
        $fileExists = in_array($fileName, $fileList);

        // 使用 cURL 写入或追加数据
        $success = $this->uploadDataWithCurl($remoteFile, $data, $fileExists);

        // 重新创建空的.status文件
        $this->createEmptyFile($remoteDir, $statusFile);

        return $success;
    }

    /**
     * 使用 cURL 上传数据到指定的文件（存在则追加，不存在则创建）。
     *
     * @param string $remoteFile 远程文件路径。
     * @param string $data 要写入的数据。
     * @param bool $append 是否追加数据（true为追加，false为新写入）。
     */
    private function uploadDataWithCurl($remoteFile, $data, $append = false) {
        $ch = curl_init();
        $tempHandle = fopen('php://temp', 'rw');
//        fwrite($tempHandle, $data . "\n");
        fwrite($tempHandle, $data);
        rewind($tempHandle);

        // 设置cURL选项
        curl_setopt($ch, CURLOPT_URL, "ftp://{$this->ftpServer}/{$remoteFile}");
        curl_setopt($ch, CURLOPT_USERPWD, "{$this->ftpUsername}:{$this->ftpPassword}");
        curl_setopt($ch, CURLOPT_UPLOAD, true);
        curl_setopt($ch, CURLOPT_USE_SSL, false);
        curl_setopt($ch, CURLOPT_INFILE, $tempHandle);
        curl_setopt($ch, CURLOPT_INFILESIZE, strlen($data));
        if ($append) {
            curl_setopt($ch, CURLOPT_APPEND, true);
        }

        // 执行cURL
        $success = curl_exec($ch);
        curl_close($ch);
        fclose($tempHandle);

        return !!$success;
    }
}
